/*
 *  Filename:lsv_volume_gc.c
 *  Description:
 *
 *  Created on: 2017年3月13日
 *  Author: Asdf(825674301)
 */
#include "config.h"

#include <sys/types.h>
#include <unistd.h>

#define DBG_SUBSYS S_LIBSTORAGE

#include "dbg.h"
#include "lsv_help.h"
#include "lsv_volume.h"
#include "lsv_volume_gc.h"

// off, bs(block size)具有相同的粒度
// block索引，第几个block？

#define BLOCK_IDX(off, bs) ((off) / (bs))

// block内偏移, len为每个元素占据的基本单元的长度
#define BLOCK_OFF(off, bs) ((off) % (bs))

// off对齐到block边界
#define BLOCK_BASE(off, bs) ((off) / (bs) * (bs))


static inline uint32_t __chunk_id_2_dirty_idx(uint32_t chunk_id) {
        uint32_t storage_chkid, storage_offset, storage_bitmap_pos;

        storage_chkid = chunk_id / LSV_VOLGC_CHUNK_RECORD_NUM;
        storage_offset = (chunk_id % LSV_VOLGC_CHUNK_RECORD_NUM) * LSV_VOLGC_STORAGE_BIT_LEN / 8;

        // 对齐到页边界
        storage_offset = storage_offset / LSV_PAGE_SIZE * LSV_PAGE_SIZE;
        storage_bitmap_pos = storage_chkid * LSV_CHUNK_SIZE + storage_offset;

        return storage_bitmap_pos / LSV_PAGE_SIZE;
}

static inline void __lsv_volume_bitmap_set_dirty(lsv_u8_t *dirty_page_bitmap, lsv_u32_t chunk_id) {
        uint32_t idx = __chunk_id_2_dirty_idx(chunk_id);

        assert(((idx) >> 3) < LSV_VOLGC_STORAGE_BITMAP_DIRTY_BITMAP_NUM);
        dirty_page_bitmap[(idx) >> 3] |= (lsv_u8_t) (1 << ((lsv_u8_t) (idx) & (lsv_u8_t) 7));
}

static inline void __lsv_volume_bitmap_clean_dirty(lsv_u8_t *dirty_page_bitmap, lsv_u32_t idx) {
        assert(((idx) >> 3) < LSV_VOLGC_STORAGE_BITMAP_DIRTY_BITMAP_NUM);
        dirty_page_bitmap[(idx) >> 3] &= (lsv_u8_t) (~(1 << ((lsv_u8_t) (idx) & (lsv_u8_t) 7)));
}

static inline lsv_u8_t __lsv_volume_bitmap_get_dirty(lsv_u8_t *dirty_page_bitmap, lsv_u32_t idx) {
        assert(((idx) >> 3) < LSV_VOLGC_STORAGE_BITMAP_DIRTY_BITMAP_NUM);
        return dirty_page_bitmap[(idx) >> 3] & ((lsv_u8_t) (1 << ((lsv_u8_t) (idx) & (lsv_u8_t) 7)));
}

int lsv_volume_bitmap_malloc(lsv_volume_proto_t *lsv_info, lsv_u32_t chunk_id, lsv_u8_t type) {

        lsv_volgc_info_t * volgc_info = NULL;
        lsv_u32_t bitmap_pos;
        lsv_u8_t bitmap_mask;

        assert(chunk_id < LSV_MAX_CHUNK_NUM);

        volgc_info = lsv_info->volgc_info;
        // 对应哪一个byte？
        bitmap_pos = chunk_id / (8 / LSV_VOLGC_STORAGE_BIT_LEN);

        bitmap_mask = (type | 0x02) << (chunk_id % (8 / LSV_VOLGC_STORAGE_BIT_LEN) * LSV_VOLGC_STORAGE_BIT_LEN);
        volgc_info->bitmaps[bitmap_pos] |= bitmap_mask; // set type in first malloc

        DINFO("chunk_id:%u type:%u <%u,%u> %u mask %u\n", chunk_id, type, bitmap_pos, bitmap_mask,
              volgc_info->bitmaps[bitmap_pos], (type|0x02));

        __lsv_volume_bitmap_set_dirty(volgc_info->dirty_page_bitmap, chunk_id);
        return 0;
}

int lsv_volume_bitmap_free(lsv_volume_proto_t *lsv_info, lsv_u32_t chunk_id, lsv_u8_t type) {

        lsv_volgc_info_t * volgc_info = NULL;
        lsv_u32_t bitmap_pos;
        lsv_u8_t bitmap_mask;

        assert(chunk_id < LSV_MAX_CHUNK_NUM);

        volgc_info = lsv_info->volgc_info;
        bitmap_pos = chunk_id / (8 / LSV_VOLGC_STORAGE_BIT_LEN);

        // 0x02: 清除高位的1
        // 0x03: 清除两位
        bitmap_mask = (((lsv_u8_t) 0x03) << (chunk_id % (8 / LSV_VOLGC_STORAGE_BIT_LEN) * LSV_VOLGC_STORAGE_BIT_LEN));
        volgc_info->bitmaps[bitmap_pos] &= ~bitmap_mask;

        DINFO("chunk_id:%u type:%u <%u,%u> %u mask %u\n", chunk_id, type, bitmap_pos, bitmap_mask,
              volgc_info->bitmaps[bitmap_pos], 0x03);

        __lsv_volume_bitmap_set_dirty(volgc_info->dirty_page_bitmap, chunk_id);
        return 0;
}

int lsv_volume_bitmap_batch_set(lsv_volume_proto_t *lsv_info, lsv_u32_t count, lsv_u32_t *chunk_id) {

        int ret = 0;
        lsv_volgc_info_t *volgc_info = NULL;
        lsv_u32_t storage_chkid, storage_offset, storage_bitmap_pos, page_idx;
        lsv_volume_io_t vio;

        volgc_info = lsv_info->volgc_info;

        for (uint32_t i = 0; i < count; i++) {
                storage_chkid = chunk_id[i] / LSV_VOLGC_CHUNK_RECORD_NUM;
                storage_offset = (chunk_id[i] % LSV_VOLGC_CHUNK_RECORD_NUM) * LSV_VOLGC_STORAGE_BIT_LEN / 8 / LSV_PAGE_SIZE * LSV_PAGE_SIZE;
                storage_bitmap_pos = storage_chkid * LSV_CHUNK_SIZE + storage_offset;
                page_idx = storage_bitmap_pos / LSV_PAGE_SIZE;

                DINFO("volgc prepare set bitmaps %u/%u chunk_id:%u,<%u,%u,%u>\n", i, count, chunk_id[i],
                      storage_chkid + LSV_VOLGC_STORAGE_SET_BASE, storage_offset, storage_bitmap_pos);

                // 如所在页脏，则写入，并清除dirty bit
                if (__lsv_volume_bitmap_get_dirty(volgc_info->dirty_page_bitmap, page_idx)) {
                        DINFO("set bitmap %u/%u chunk_id:%u,<%u,%u,%u>\n", i, count, chunk_id[i],
                              storage_chkid + LSV_VOLGC_STORAGE_SET_BASE, storage_offset, storage_bitmap_pos);
                        //set
                        lsv_volume_io_init(&vio, storage_chkid + LSV_VOLGC_STORAGE_SET_BASE, storage_offset,
                                           LSV_PAGE_SIZE,
                                           LSV_VOLGC_STORAGE_TYPE);
                        ret = lsv_volume_chunk_update(lsv_info, &vio, (lsv_s8_t *)&volgc_info->bitmaps[storage_bitmap_pos]);
                        if (unlikely(ret)) {
                                DERROR("set bitmap err, ret %d\n", ret);
                                // TODO core 当别的节点故障时，ret == 11, 如何处理这个错误？
                                GOTO(err_ret, ret);
                        }

                        __lsv_volume_bitmap_clean_dirty(volgc_info->dirty_page_bitmap, page_idx);
                }
        }

        return 0;
err_ret:
        return ret;
}
